#include "util.hpp"

extern "C" {
#include "lj_obj.h"
#include "lj_lib.h"
#include "lj_err.h"
}

#define abs_index(L, i) \
  ((i) > 0 || (i) <= LUA_REGISTRYINDEX ? (i) : lua_gettop(L) + (i) + 1)

  

inline TValue* index2adr(lua_State* L, int idx)
{
	return (idx > 0 ? L->base + (idx - 1) : L->top + idx);
}

void* lua_check_object(lua_State* L, int idx, int tag, char const* extramsg)
{
	TValue* p = index2adr(L, idx);
	if (!(p < L->top && tvisudata(p) &&
		udataV(p)->udtype == tag))
		lj_err_argtype(L, idx, extramsg);
	return uddata(udataV(p));
}

void* lua_try_object(lua_State* L, int idx, int tag)
{
	TValue* p = index2adr(L, idx);
	if (!(p - L->base && tvisudata(p) &&
		udataV(p)->udtype == tag))
		return 0;
	return uddata(udataV(p));
}

void* lua_create_object(lua_State* L, int tag, int size)
{
	void* obj = lua_newuserdata(L, size);
	GCudata *ud = udataV(L->top-1);
	ud->udtype = tag;
	setgcrefr(ud->metatable, curr_func(L)->c.env);
	return obj;
}

void* lua_create_object_no_mt(lua_State* L, int tag, int size)
{
	void* obj = lua_newuserdata(L, size);
	GCudata *ud = udataV(L->top-1);
	ud->udtype = tag;
	return obj;
}

void lua_clear_object_tag(lua_State* L, int idx)
{
	TValue* p = index2adr(L, idx);

	if (!(p < L->top && tvisudata(p)))
		lj_err_argtype(L, idx, "expected userdata");

	GCudata *ud = udataV(p);
	ud->udtype = UDTYPE_USERDATA;
}